﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;

namespace UtilZ.Dotnet.WindowsDesktopEx.WPF
{
    /// <summary>
    /// WPF辅助类
    /// </summary>
    public static class WPFHelper
    {
        /// <summary>
        /// 判断UI是否处于设计模式[处理设计模式返回true;否则返回false]
        /// </summary>
        /// <param name="ele">要判断的UI元素</param>
        /// <returns>处理设计模式返回true;否则返回false</returns>
        public static bool IsInDesignMode(this UIElement ele)
        {
            if (ele == null)
            {
                throw new ArgumentNullException(nameof(ele));
            }

            //非UI对象，要判断是否处于设计器模式
            //bool isInDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject());

            //UI对象，要判断是否处于设计器模式
            //bool isInDesignMode = DesignerProperties.GetIsInDesignMode(ele);

            //这两种方式有时会失效（具体什么情况下会失效不明）
            //return (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue;

            return DesignerProperties.GetIsInDesignMode(ele);
        }



        /// <summary>
        /// 判断当前窗口是否已释放[返回值:true:已释放Invoke;false:未释放]
        /// </summary>
        /// <param name="window">要判判断的窗口</param>
        /// <returns>返回值:true:已释放Invoke;false:未释放</returns>
        public static bool IsDisposed(this Window window)
        {
            if (window == null)
            {
                throw new ArgumentNullException(nameof(window));
            }

            return new System.Windows.Interop.WindowInteropHelper(window).Handle == IntPtr.Zero;
        }



        /// <summary>
        /// 判断当前操作是否需要调用Invoke[返回值:true:调用Invoke;false:不需要]
        /// </summary>
        /// <param name="dispatcher">判断的对象</param>
        /// <returns>返回值:true:调用Invoke;false:不需要</returns>
        public static bool InvokeRequired(this System.Windows.Threading.DispatcherObject dispatcher)
        {
            if (dispatcher == null)
            {
                throw new ArgumentNullException(nameof(dispatcher));
            }

            return !dispatcher.Dispatcher.CheckAccess();
        }



        /// <summary>
        /// Determines whether the text box or drop-down portion of the
        /// <see cref="T:System.Windows.Controls.AutoCompleteBox" /> control has
        /// focus.
        /// </summary>
        /// <returns>true to indicate the
        /// <see cref="T:System.Windows.Controls.AutoCompleteBox" /> has focus;
        /// otherwise, false.</returns>
        public static bool HasFocus(UIElement control)
        {
            DependencyObject focused =
#if SILVERLIGHT
                FocusManager.GetFocusedElement() as DependencyObject;
#else
                // For WPF, check if the element that has focus is within the control, as
                // FocusManager.GetFocusedElement(this) will return null in such a case.
                control.IsKeyboardFocusWithin ? Keyboard.FocusedElement as DependencyObject : FocusManager.GetFocusedElement(control) as DependencyObject;
#endif
            while (focused != null)
            {
                if (object.ReferenceEquals(focused, control))
                {
                    return true;
                }

                // This helps deal with popups that may not be in the same 
                // visual tree
                DependencyObject parent = VisualTreeHelper.GetParent(focused);
                if (parent == null)
                {
                    // Try the logical parent.
                    FrameworkElement element = focused as FrameworkElement;
                    if (element != null)
                    {
                        parent = element.Parent;
                    }
                }
                focused = parent;
            }

            return false;
        }



        /// <summary>
        /// 查找元素根窗口
        /// </summary>
        /// <param name="element">目标控件</param>
        ///  <param name="targetWindowType">父窗口类型,不为null时查找与该类型匹配的父窗口;为null时找到第一级为结果</param>
        /// <returns>查找结果</returns>
        public static Window FindParentForm(FrameworkElement element, Type targetWindowType = null)
        {
            if (element == null)
            {
                return null;
            }

            Window window = Window.GetWindow(element);
            if (window != null)
            {
                return window;
            }

            FrameworkElement framework = element.Parent as FrameworkElement;
            DependencyObject dependency;
            while (framework != null)
            {
                dependency = LogicalTreeHelper.GetParent(framework);
                if (dependency != null && dependency is Window)
                {
                    return (Window)dependency;
                }
            }

            Type controlType = typeof(FrameworkElement);
            framework = element.Parent as FrameworkElement;

            while (framework != null)
            {
                if (framework.GetType() == controlType)
                {
                    break;
                }

                if (framework is Window &&
                    (targetWindowType == null || framework.GetType() == targetWindowType))
                {
                    return (Window)framework;
                }

                framework = framework.Parent as FrameworkElement;
            }

            return null;
        }



        /// <summary>
        /// 查找指定控件模板里的子控件,未找到返回null
        /// </summary>
        /// <param name="control">目标控件</param>
        /// <param name="predicate">匹配条件</param>
        /// <returns>模板里的子控件</returns>
        public static Visual FindTemplateControl(DependencyObject control, Func<Visual, bool> predicate)
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }

            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            int count = VisualTreeHelper.GetChildrenCount(control);
            DependencyObject obj;
            Visual child;
            for (int i = 0; i < count; i++)
            {
                obj = VisualTreeHelper.GetChild(control, i);
                child = obj as Visual;
                if (child != null && predicate(child))
                {
                    return child;
                }

                child = FindTemplateControl(obj, predicate);
                if (child != null)
                {
                    return child;
                }
            }

            return null;
        }

        /// <summary>
        /// 查找指定控件模板里的子控件,未找到返回null
        /// </summary>
        /// <param name="dependencyObject">目标控件</param>
        /// <param name="name">模板内子控件名称</param>
        /// <returns>模板里的子控件</returns>
        public static FrameworkElement FindTemplateControlByName(DependencyObject dependencyObject, string name)
        {
            if (dependencyObject == null)
            {
                throw new ArgumentNullException(nameof(dependencyObject));
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            var controll = dependencyObject as Control;
            if (controll != null)
            {
                return controll.Template.FindName(name, controll) as FrameworkElement;
            }

            int count = VisualTreeHelper.GetChildrenCount(dependencyObject);
            DependencyObject obj;
            FrameworkElement child;
            for (int i = 0; i < count; i++)
            {
                obj = VisualTreeHelper.GetChild(dependencyObject, i);
                child = obj as FrameworkElement;
                if (child != null && string.Equals(child.Name, name))
                {
                    return child;
                }

                child = FindTemplateControlByName(obj, name);
                if (child != null)
                {
                    return child;
                }
            }

            return null;
        }

        /// <summary>
        /// 获取指定控件模板里的子控件列表
        /// </summary>
        /// <param name="control">目标控件</param>
        /// <returns>模板里的子控件列表</returns>
        public static List<Visual> GetTemplateControlList(DependencyObject control)
        {
            if (control == null)
            {
                throw new ArgumentNullException(nameof(control));
            }

            List<Visual> visualList = new List<Visual>();
            PrimitiveGetTemplateControlList(control, visualList);
            return visualList;
        }
        private static void PrimitiveGetTemplateControlList(DependencyObject control, List<Visual> visualList)
        {
            int count = VisualTreeHelper.GetChildrenCount(control);
            if (count == 0)
            {
                return;
            }

            DependencyObject obj;
            Visual child;
            for (int i = 0; i < count; i++)
            {
                obj = VisualTreeHelper.GetChild(control, i);
                child = obj as Visual;
                if (child != null)
                {
                    visualList.Add(child);
                    PrimitiveGetTemplateControlList(obj, visualList);
                }
                else
                {
                    PrimitiveGetTemplateControlList(obj, visualList);
                }
            }
        }




        /// <summary>
        /// 获取父控件中命中的子控件
        /// </summary>
        /// <typeparam name="T">子控件类型</typeparam>
        /// <param name="element">父控件</param>
        /// <param name="point">父控件中的命中坐标</param>
        /// <returns>命中的子控件</returns>
        public static T GetInputHitTestChildControl<T>(UIElement element, Point point) where T : FrameworkElement
        {
            var target = element.InputHitTest(point) as DependencyObject;
            T result = null;
            while (target != null)
            {
                if (target is T)
                {
                    result = (T)target;
                    break;
                }
                else
                {
                    target = VisualTreeHelper.GetParent(target);
                }
            }

            return result;
        }



        //private const string USER32DLL = "USER32.dll";
        //private const UInt32 CLOSE = 0xf060;
        //private const UInt32 MF_BYCOMMAND = 0x0;

        //[DllImport(USER32DLL, CharSet = CharSet.Unicode)]
        //private static extern IntPtr GetSystemMenu(IntPtr hwnd, UInt32 revert);

        //[DllImport(USER32DLL, CharSet = CharSet.Unicode)]
        //private static extern IntPtr RemoveMenu(IntPtr hMenu, UInt32 position, UInt32 flags);

        //public static void Hiden(Window window)
        //{
        //    var hwnd = new WindowInteropHelper(window).Handle;
        //    IntPtr hMenu = GetSystemMenu(hwnd, 0);
        //    RemoveMenu(hMenu, CLOSE, MF_BYCOMMAND);
        //}


        /// <summary>
        /// 清空DataGrid选中项
        /// </summary>
        /// <param name="dataGrid">DataGrid</param>
        public static void ClearSelectedItems(DataGrid dataGrid)
        {
            dataGrid.UpdateLayout();
            DataGridRow dataGridRow;

            for (int i = 0; i < dataGrid.Items.Count; i++)
            {
                dataGridRow = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i);
                if (dataGridRow != null)
                {
                    dataGridRow.IsSelected = false;
                }
            }
        }


        /// <summary>
        /// 获取DataGrid指定索引行
        /// </summary>
        /// <param name="dataGrid">DataGrid</param>
        /// <param name="rowIndex">索引</param>
        /// <returns>索引行</returns>
        public static DataGridRow GetDataGridRow(DataGrid dataGrid, int rowIndex)
        {
            DataGridRow dataGridRow = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex);
            if (dataGridRow == null)
            {
                dataGrid.UpdateLayout();
                dataGridRow = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex);
                dataGridRow.IsSelected = true;
            }

            return dataGridRow;
        }



        /// <summary>
        /// 设置DataGrid选中项
        /// </summary>
        /// <param name="dataGrid">DataGrid</param>
        /// <param name="selectedItem">选中项</param>
        public static void SetSelectedItemFirstRow(DataGrid dataGrid, object selectedItem)
        {
            if (dataGrid == null || dataGrid.Items == null || dataGrid.Items.Count < 1)
            {
                return;
            }

            dataGrid.Focus();
            dataGrid.SelectedItem = selectedItem;
            dataGrid.CurrentColumn = dataGrid.Columns.FirstOrDefault();
            dataGrid.ScrollIntoView(dataGrid.SelectedItem, dataGrid.CurrentColumn);
            dataGrid.UpdateLayout();
        }
    }
}
